﻿using System;  
using System.Linq;
using System.Text;  
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.Collections.Generic;

namespace DevelopAssistant.Common
{
    /// <summary>
    /// C# 编译
    /// </summary>
    public class CSharpCompiler
    {
        public enum OutputType { DLL, EXE };
        private string code;
        private string name;
        private string filepath;
        private OutputType output;
        private bool successfull = false;
        private List<string> errors = new List<string>();
        private List<string> warnings = new List<string>();
        private string[] sources = null;
        /// <summary>
        /// The code that will be compiled.
        /// </summary>
        public string SourceCode
        {
            set
            {
                code = value;
            }
            get
            {
                return code;
            }
        }
        /// <summary>
        /// An array of multiple source code that will be compiled.
        /// </summary>
        public string[] SourceCodes
        {
            set
            {
                sources = value;
            }
            get
            {
                return sources;
            }
        }
        /// <summary>
        /// Gets a collection of compiler errors if any.
        /// </summary>
        public string[] CompilerErrors
        {
            get
            {
                return errors.ToArray();
            }
        }
        /// <summary>
        /// Gets a collection of compiler warnings.
        /// </summary>
        public string[] CompilerWarnings
        {
            get
            {
                return null;
            }
        }
        /// <summary>
        /// Set or gets the output type.
        /// </summary>
        public OutputType Output
        {
            set
            {
                output = value;
            }
            get
            {
                return output;
            }
        }
        /// <summary>
        /// Gets or sets the file path of where to save the assembly.
        /// </summary>
        public string Path
        {
            set
            {
                filepath = value;
            }
            get
            {
                return filepath;
            }
        }
        /// <summary>
        /// Sets or gets the name of the assembly output.
        /// </summary>
        public string NameOfAssembly
        {
            set
            {
                name = value;
            }
            get
            {
                return name;
            }
        }
        /// <summary>
        /// Gets whether it was a successfull compilation.
        /// </summary>
        public bool SuccessfullCompilation
        {
            get
            {
                return successfull;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public void CompileMultipleCodeFiles()
        {
            using (var provider = new CSharpCodeProvider())
            {
                System.CodeDom.Compiler.ICodeCompiler compiler = provider.CreateCompiler();
                System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters();
                if (this.Output == OutputType.DLL)
                {
                    parameters.GenerateExecutable = false;
                    parameters.OutputAssembly = filepath + "\\" + this.NameOfAssembly + ".dll";
                }
                else if (this.Output == OutputType.EXE)
                {
                    parameters.GenerateExecutable = true;
                    parameters.OutputAssembly = filepath + "\\" + this.NameOfAssembly + ".exe";
                }
                CompilerResults results = compiler.CompileAssemblyFromSourceBatch(parameters, this.SourceCodes);
                CompilerErrorCollection errorcollection = results.Errors;
                foreach (CompilerError error in errorcollection)
                {
                    if (error.IsWarning == true)
                    {
                        warnings.Add("Line: " + error.Line.ToString() + " Warning Number: " + error.ErrorNumber + " Warning Message: " + error.ErrorText);
                    }
                    else if (error.IsWarning == false)
                    {
                        errors.Add("Line: " + error.Line.ToString() + " Error Number: " + error.ErrorNumber + " Error Message: " + error.ErrorText);
                    }
                }
                if (errorcollection.Count == 0)
                {
                    this.successfull = true;
                }

            }
            return;
        }
        /// <summary>
        /// 
        /// </summary>
        public void CompileCode()
        {
            using (var provider = new CSharpCodeProvider())
            {
                System.CodeDom.Compiler.ICodeCompiler compiler = provider.CreateCompiler();
                System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters();
                if (this.Output == OutputType.DLL)
                {
                    parameters.GenerateExecutable = false;
                    parameters.OutputAssembly = filepath + "\\" + this.NameOfAssembly + ".dll";
                }
                else if (this.Output == OutputType.EXE)
                {
                    parameters.GenerateExecutable = true;
                    parameters.OutputAssembly = filepath + "\\" + this.NameOfAssembly + ".exe";
                }
                CompilerResults results = compiler.CompileAssemblyFromSource(parameters, this.SourceCode);
                CompilerErrorCollection errorcollection = results.Errors;
                foreach (CompilerError error in errorcollection)
                {
                    if (error.IsWarning == true)
                    {
                        warnings.Add("Line: " + error.Line.ToString() + " Warning Number: " + error.ErrorNumber + " Warning Message: " + error.ErrorText);
                    }
                    else if (error.IsWarning == false)
                    {
                        errors.Add("Line: " + error.Line.ToString() + " Error Number: " + error.ErrorNumber + " Error Message: " + error.ErrorText);
                    }
                }
                if (errorcollection.Count == 0)
                {
                    this.successfull = true;
                }

            }
        }
    
    }
}
